package com.ruoyi.framework.interceptor;

import com.ruoyi.common.annotation.CreateBy;
import com.ruoyi.common.annotation.CreateTime;
import com.ruoyi.common.annotation.UpdateBy;
import com.ruoyi.common.annotation.UpdateTime;
import com.ruoyi.common.core.domain.BaseEntity;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import org.apache.ibatis.binding.MapperMethod;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;

import java.lang.reflect.Field;
import java.util.List;
import java.util.Properties;

/**
 * @author zhou
 * @version V1.0.0
 * @title tianaceae-intelligent
 * @created 2023-3-29 16:45
 * @description mybatis自动填充拦截器
 **/
@Intercepts({
    @Signature(
        method = "update",
        type = Executor.class,
        args = {
            MappedStatement.class, Object.class
        })
})
public class AutoFillInterceptor implements Interceptor {

    /**
     * 需要排除的方法
     * 以下集合中的方法不执行拦截器
     */
    List<String> excludeMethods = List.of(
            "insertLogininfor", "updateUser", "updateDeptChildren", "updateDeptStatusNormal",
            "updateDictDataType", "insertOperlog", "insertJobLog");


    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // 获取有关SQL信息对象 - MappedStatement
        MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
        // 获取有关CRUD信息对象 - SqlCommandType
        SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();
        // 获取SQL对象执行的完整路径
        String mappedStatementId = mappedStatement.getId();
        // 获取SQL对象当前调用的方法名称
        String mappedStatementMethodName = mappedStatementId.substring(mappedStatementId.lastIndexOf(".") + 1);
        // 排序不需要执行拦截器的方法updateDictDataType
        if(!excludeMethods.contains(mappedStatementMethodName)) {
            // 判断执行INSERT || UPDATE的操作
            if (SqlCommandType.INSERT.equals(sqlCommandType) || SqlCommandType.UPDATE.equals(sqlCommandType))
            {
                // 获取当前调用方法中参数
                Object parameter = invocation.getArgs()[1];
                // 批量操作时
                if (parameter instanceof MapperMethod.ParamMap)
                {
                    MapperMethod.ParamMap map = (MapperMethod.ParamMap) parameter;
                    Object obj = map.get("list");
                    List<?> list = (List<?>) obj;
                    if (list != null) {
                        for (Object o : list) {
                            setParameter(o, sqlCommandType);
                        }
                    }
                } else {
                    setParameter(parameter, sqlCommandType);
                }
            }
        }
        return invocation.proceed();
    }

    public void setParameter(Object parameter, SqlCommandType sqlCommandType) throws Throwable {
        Field[] declaredFields;
        Class<?> aClass = parameter.getClass();
        //如果常用字段提取了公共类 BaseEntity 判断BaseEntity是否是父类
        if (BaseEntity.class.isAssignableFrom(aClass)) {
            // 获取父类私有成员变量
            declaredFields = aClass.getSuperclass().getDeclaredFields();
        } else {
            // 获取私有成员变量
            declaredFields = aClass.getDeclaredFields();
        }
        for (Field field : declaredFields) {
            if (SqlCommandType.INSERT.equals(sqlCommandType)) {
                // insert 语句插入 createBy
                if (field.getAnnotation(CreateBy.class) != null) {
                    field.setAccessible(true);
                    field.set(parameter, SecurityUtils.getUsername());
                }
                // insert 语句插入 createTime
                if (field.getAnnotation(CreateTime.class) != null) {
                    field.setAccessible(true);
                    field.set(parameter, DateUtils.getNowDate());
                }
            }

            if (SqlCommandType.UPDATE.equals(sqlCommandType)) {
                // update 语句插入 updateBy
                if (field.getAnnotation(UpdateBy.class) != null) {
                    field.setAccessible(true);
                    field.set(parameter, SecurityUtils.getUsername());
                }
                // update 语句插入 updateTime
                if (field.getAnnotation(UpdateTime.class) != null) {
                    field.setAccessible(true);
                    field.set(parameter, DateUtils.getNowDate());
                }
            }
        }
    }

    @Override
    public Object plugin(Object target) {
        return Interceptor.super.plugin(target);
    }

    @Override
    public void setProperties(Properties properties) {
        Interceptor.super.setProperties(properties);
    }
}
